/* typehints:start */
import { GameRoot } from "../root";
import { People } from "../people";
/* typehints:end */

import { clamp, copyObj, createID, getObjectType, ObjectDeleteValArray0, ObjectNeedKey } from "../../core/utils/utils";
import { GoodLevelDefine, GoodLevelGradeDefine, GoodTypeDefine } from "../defines/good_type";
import { getSideHustleLevel } from "../defines/side_hustle";
import { attrDefine } from "../defines/attr_define";
import { MoneyDefine } from "../defines/money_define";

const _id = createID();

export class GoodAttr{
  constructor(data = {}){
    this.worldPos = data.worldPos || [0, 0];
    this.mapPos = data.mapPos || [0, 0];
    // 世界上是否存活，也就是是否需要显示
    this.isLive = data.isLive !== undefined ? data.isLive : true;
    // 是否需要保存数据
    this.isSave = data.isSave !== undefined ? data.isSave : true;

    // 关于这个道具的多样数据
    this.data = {
      num: 1,
			backdropGoods: [],
			// 这个等级仅表示该物品在该稀有度下的上中下分级，0为无等级，123分别为下中上品
			[GoodLevelDefine.grade.key]: 0,
      ...(data.data)
    };
  }
}

/**
 * 定义物品类
 */
export class Goods {
	constructor(root, storeId, attachGoodAttr = {}, isGenerate = false) {
		// 在地图编辑器中的编号，全局唯一
		this.storeId = storeId;
		// 生成物品时，附加在物品属性的内容
		this.attachGoodAttr = attachGoodAttr;
		// 是否为系统自动生成物品，如果是，那么将会记录在存档中
		this.isGenerate = isGenerate;

		/** @type {GameRoot} */
		this.root = root;

		// 当前good的key
		this.key = null;

		this.attr = null;

		/** @type {HTMLElement} */
		this.element = null;

		// 在背包中的id
		this.backpackId = null;

		// 装备在哪个肢体上
		this.peopleLimb = null;

		// 组件，实现不同功能，根据需求插入
		this.components = null;

		// 临时ID
		this._id = _id();
	}

	initialize(key) {
		let saveData = this.root.itemData.goodData[this.storeId];
		this.key = key;

		if (saveData) {
			this.attr = new GoodAttr({ ...ObjectDeleteValArray0(saveData) });
		} else {
			this.internalGetDefaultData();
			this.attr = new GoodAttr({ ...this.attachGoodAttr });
		}

		this.saveGoodData();
	}

	/**
	 * 修改good的数据，并保存
	 * @param {*} cb
	 */
	saveGoodData(cb) {
		cb && cb(this.attr);
		if (!this.attr.isSave || !this.storeId) return;

		// 如果该物品是额外生成的内容并且在世界存在，那么将其数据保存
		// 如果不在世界存在，那么不保存，因为不在世界的时候该物品数据将会被删除
		if(this.getIsExtra() && this.attr.isLive){
			this.root.itemData[this.getStoreData()][this.storeId] = this.getData();
		} else if(!this.getIsExtra()){
			this.root.itemData[this.getStoreData()][this.storeId] = this.attr;
		}

		this.root.saveItemData();
	}

	/**
	 * 将自己给予玩家需要的数据
	 */
	getData() {
		let attr = null;
		if (!this.attr.isLive) {
			attr = ObjectNeedKey(this.attr, ["isLive", "data"]);
		} else {
			attr = this.attr;
		}

		return {
			key: this.key,
			attr: copyObj(attr),
		};
	}

	/**
	 * 生灵使用该物品判断是否匹配需求属性
	 * @param {People} people 
	 */
	getPeopleMatchNeedAttr(people){
		let needAttr = this.getNeedAttr();
		let errors = false;

		Object.keys(needAttr).map(key => {
			let data = people.data.attr[key] || people.data.basicAttr[key] || people.data.useAttr[key] || 0;
			if(data < needAttr[key]){
				if(getObjectType(errors) == 'Boolean') errors = []; 
				errors.push(`${attrDefine[key].text}需要${needAttr[key]}`)
			}
		})

		return errors;
	}

	update() {
    this.root.time.run(`good-update-${this._id}`, () => {
			this.getExctraInfo();
		}, 100)
	}

	/**
	 * --------------------   物品属性获取   ----------------------
	 */

	getTitle() {
		abstract;
	}

	getExctraInfo() {
		let text = [];

		if(this.attr.data.num > 1){
			text.push(`堆叠${this.attr.data.num}`)
		}

		let control = this.root.mainPlayer.control;
		if (control && control.good == this && control.sideHustle) {
			let time = this.root.time.getRunTime(`player-control-${control.id}`);
			text.push(`正在${control.text}中，还需${Math.ceil(time / 1000)}s`);
		}

		if (this.element) {
			this.element.querySelector(".min-text").innerHTML = text.join("、");
		}
	}

	getDesc() {
		abstract;
	}

	getType() {
		return GoodTypeDefine.sundries.key;
	}

	getIsExtra(){
		return this.storeId && ('' + this.storeId).indexOf('extra') > -1;
	}

	getStoreData(){
		return this.getIsExtra() ? 'extraGoods' : 'goodData';
	}

	// 物品的默认属性
	getDefaultAttr() {
		return {};
	}

	/**
	 * 获取该物品的稀有度
	 * @returns 
	 */
	getLevel(){
		return GoodLevelDefine.level1.key;
	}

	/**
	 * 获取该物品的稀有度名称
	 * @returns 
	 */
	getLevelDesc(){
		let grade = GoodLevelGradeDefine[clamp(this.attr.data.grade, 0, GoodLevelGradeDefine.length - 1)];

		return GoodLevelDefine[this.getLevel()].text + (grade == '' ? '' : `[${grade}]`);
	}

	/**
	 * 设置默认的多样数据值
	 * @returns 
	 */
	getDefaultData(){
		return {};
	}

	// 获取计算后的参数
	// 这里可以计算动态的值返回
	// 比如天赋对该物品的影响
	getAttr(key = false, defaultValue = false) {
		let attr = this.getDefaultAttr();

		if(key){
			return attr[key] || defaultValue;
		}

		return attr;
	}

	// 使用这样物品需要玩家的属性
	getNeedAttr() {
		return {};
	}

	/**
	 * 是否可以装备在人物上，值为生灵肢体
	 * @returns
	 */
	getIsEquip() {
		return false;
	}

	/**
	 * 是否当做药品使用
	 * @returns
	 */
	getIsDrugs() {
		return false;
	}

	/**
	 * 是否可以当做弹药发射
	 * @returns
	 */
	getIsLaunch() {
		return false;
	}

	/**
	 * 只有指定种族才能使用
	 * @returns 
	 */
	getIsRace(){
		return false;
	}

	/**
	 * 特殊效果描述
	 * @returns
	 */
	getSpecialInfo() {
		return "";
	}

	// 是否可堆叠
	getIsStack() {
		return false;
	}

	/**
	 * 需要什么样副业获取
	 * @returns
	 */
	getSideHustle() {
		return false;
	}

	getControls() {
		return [];
	}

	/**
	 * 获得该物品价格
	 */
	getPrice(){
		return {
			type: MoneyDefine.money.key,
			price: 0
		};
	}

	/**
	 * 获取该物品默认的库存
	 */
	getDefaultInventory(){
		return () => [];
	}

	/**
	 * 库存中的物品是否占有重量
	 * @returns 
	 */
	getInventoryIsWeight(){
		return true;
	}

	getAllWeight(){
    let weight = (this.getAttr()[attrDefine.weight.key] || 1) * this.num;
    if(this.getInventoryIsWeight()){
      this.attr.data.backdropGoods.map(item => {
        let good = this.root.worldMap.getGood(item.key);
        weight += (good.getAttr()[attrDefine.weight.key] || 1) * item.num;
      })
    }

		return weight;
	}

	/**
	 * 返回组件类
	 * @returns 
	 */
	getComponents(){
		return [];
	}

	/**
	 * 执行这个函数在组件中的功能，并且同时执行自己身上的。
	 * 组件可以覆盖自身，同时根据组件顺序执行
	 * 当组件中的函数返回值不为undefined时，将会直接断开执行，直接返回值
	 * @param {*} name 
	 */
	runComponent(name, isStep = false){
		let components = this.internalGetComponents();

		if(!isStep){
			this[name] && this[name]();
		}
		for(let i = 0; i < components.length; i++){
			let data = components[i][name] && components[i][name]();
			if(data !== undefined){
				return data;
			}
		}
	}

	/**
	 * --------------------   物品内部方法   ----------------------
	 */

	get num(){
		return this.attr.data.num;
	}

	internalGetDefaultData(){
		let result = {
			backdropGoods: this.getDefaultInventory()(this, this.attachGoodAttr),
			...this.getDefaultData()
		}
		if(!this.attachGoodAttr.data) this.attachGoodAttr.data = {};
		Object.keys(result).map(key => {
			if(!this.attachGoodAttr.data[key]) this.attachGoodAttr.data[key] = result[key]
		})
	}

	internalGetComponents(){
		if(this.components){
			return this.components;
		} else {
			let components = this.getComponents();
			this.components = components.map(item => new (item)(this.root, this));
			return this.components;
		}
	}

	/**
	 * 填入消耗物品数量
	 */
	internalConsumeGoodNum(text = '使用'){
		return new Promise((resolve, reject) => {
			let { confirm } = this.root.gameState.dialogs.showInput(text + '数量', [
				{
					key: 'num',
					text: '数量',
					value: this.attr.data.num,
					focus: true
				}
			]);
	
			confirm.add(data => {
				resolve(data.num);
			})
		})
	}

	/**
	 * 执行操作需要的必须数据，执行等待时间、副业必须等级
	 */
	internalControlSideHustle(controlKey) {
		let type = (this[`get${controlKey}SideHustle`] || (() => false))();
		let time = (this[`get${type.key}Time`] || (() => type.time))();
		let getLevel = (this[`get${type.key}Level`] || (() => type.level))();

		if (type) {
			// TODO 改为可以选择队友
			let playerSideHustle = this.root.mainPlayer.getSideHustle(type.key);
			let level = playerSideHustle
				? getSideHustleLevel(playerSideHustle.num)
				: 0;
			let effect = getLevel <= level;

			// 根据等级衰减时间
			time = time - time * (level * 10);
			return {
				text: type.text,
				effect,
				// 最少100ms获取
				time: clamp(time, 100, time),
			};
		} else {
			return false;
		}
	}

	internalGetControl() {
		let data = [];
		let controls = this.getControls().map(item => {
			let key = item.key;
			
			let confirmFn = this[`getIs${key}Confirm`];

			// 副业相关数据
			item.sideHustle = this.internalControlSideHustle(item.key);
			// 重复确认是否这个操作
			item.confirm = confirmFn ? confirmFn() : false;

			return item;
		});

		for (let i = 0; i < controls.length; i++) {
			let item = controls[i];
			let fn = this[`getControl${item.key}`];
			let conditionFn = this[`getControl${item.key}Condition`];
			if (fn && (!conditionFn || conditionFn.call(this)))
				data.push({
					...item,
					fn
				});
		}

		return data;
	}

	// 将物品销毁
	internalDestory() {
		// 如果物品是额外生成物品，那么将其删除
		if(this.getIsExtra()){
			delete this.root.itemData[this.getStoreData()][this.storeId];
		}

		this.saveGoodData((attr) => {
			attr.isLive = false;
		});
		// 重新绘制
		this.root.hud.parts.worldPage.renderGood();
		this.root.hud.parts.goodsBoard.hanldeHideGoodsBoard();

		// 如果为系统生成物品，告诉系统，这样物品减少了
		if (this.isGenerate) {
			let storeData = this.root.worldData.mapItem[this.storeId];
			storeData.num = ~~storeData.num - 1;
			this.root.saveWorldData();
		}
	}
}